﻿using System;
using System.Collections.Generic;
using System.Linq;

using Cookbook.Common;
using Cookbook.Services.Core.Commanding;
using Cookbook.Services.Core.Commands;
using Cookbook.Services.Core.Handlers;
using Cookbook.Services.Core.Persistency.NHibernate;

using FluentAssertions;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using System.Reflection;

namespace Cooking.Services.Specs.Handlers
{
    [TestClass]
    public class MapsToAggregateRootPropertiesAttributeSpecs
    {
        [TestMethod]
        public void When_command_maps_to_aggregate_root_properties_it_should_only_have_properties_equal_to_the_aggregate_root()
        {
            //-----------------------------------------------------------------------------------------------------------
            // Arrange
            //-----------------------------------------------------------------------------------------------------------
            IEnumerable<Type> commandsMappingToAggregateRootProperties =
                from t in Assembly.GetAssembly(typeof(Command)).GetTypes()
                where t.HasAttribute<MapsToAggregateRootPropertiesAttribute>()
                select t;

            //-----------------------------------------------------------------------------------------------------------
            // Assert
            //-----------------------------------------------------------------------------------------------------------
            foreach (Type command in commandsMappingToAggregateRootProperties)
            {
                When_command_maps_to_aggregate_root_properties_it_should_only_have_properties_equal_to_the_aggregate_root(command);
            }
        }

        private void When_command_maps_to_aggregate_root_properties_it_should_only_have_properties_equal_to_the_aggregate_root(Type commandType)
        {
            //-----------------------------------------------------------------------------------------------------------
            // Arrange
            //-----------------------------------------------------------------------------------------------------------
            var mappingAttribute = commandType.FindAttribute<AppliesToAggregateRootAttribute>();
            Type aggregateRootType = mappingAttribute.AggregateRootType;

            foreach (PropertyInfo commandProperty in commandType.GetProperties())
            {
                //-----------------------------------------------------------------------------------------------------------
                // Act
                //-----------------------------------------------------------------------------------------------------------
                var aggregateProperty = aggregateRootType.GetProperty(commandProperty.Name);

                if ((aggregateProperty == null) && commandProperty.Name.EndsWith(DatabaseConstants.IdentitySuffix))
                {
                    string commmandPropertyNameWithoutSuffix = commandProperty.Name.Substring(0,
                        commandProperty.Name.Length - DatabaseConstants.IdentitySuffix.Length);

                    aggregateProperty = aggregateRootType.GetProperty(commmandPropertyNameWithoutSuffix);
                }

                //-----------------------------------------------------------------------------------------------------------
                // Assert
                //-----------------------------------------------------------------------------------------------------------
                aggregateProperty.Should().NotBeNull("aggregate root {0} should have property {1} of command {2}",
                    aggregateRootType.Name, commandProperty.Name, commandType.Name);
            }
        }
    }
}
